package srdb.migration;


import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Set;

import srdb.migration.i18n.ResourceHandler;
import srdb.migration.schema.metadata.Constraint;
import srdb.migration.schema.metadata.ConstraintList;
import srdb.migration.schema.metadata.DBLink;
import srdb.migration.schema.metadata.DBObject;
import srdb.migration.schema.metadata.DataType;
import srdb.migration.schema.metadata.Domain;
import srdb.migration.schema.metadata.DomainList;
import srdb.migration.schema.metadata.Function;
import srdb.migration.schema.metadata.FunctionList;
import srdb.migration.schema.metadata.Grant;
import srdb.migration.schema.metadata.Group;
import srdb.migration.schema.metadata.Index;
import srdb.migration.schema.metadata.IndexList;
import srdb.migration.schema.metadata.ObjectType;
import srdb.migration.schema.metadata.ObjectTypeList;
import srdb.migration.schema.metadata.Package;
import srdb.migration.schema.metadata.PackageList;
import srdb.migration.schema.metadata.Procedure;
import srdb.migration.schema.metadata.ProcedureList;
import srdb.migration.schema.metadata.Role;
import srdb.migration.schema.metadata.Rule;
import srdb.migration.schema.metadata.Sequence;
import srdb.migration.schema.metadata.SequenceList;
import srdb.migration.schema.metadata.Synonym;
import srdb.migration.schema.metadata.SynonymList;
import srdb.migration.schema.metadata.Table;
import srdb.migration.schema.metadata.TableList;
import srdb.migration.schema.metadata.Trigger;
import srdb.migration.schema.metadata.TriggerList;
import srdb.migration.schema.metadata.User;
import srdb.migration.schema.metadata.View;
import srdb.migration.schema.metadata.ViewList;

public class MigrationSummary {
    public static final String TYPE_TABLE = "Table";
    public static final String TYPE_TRIGGER = "Trigger";
    public static final String TYPE_VIEW = "View";
    public static final String TYPE_SEQUENCE = "Sequence";
    public static final String TYPE_PROCEDURE = "Procedure";
    public static final String TYPE_FUNCTION = "Function";
    public static final String TYPE_CONSTRAINT = "Constraint";
    public static final String TYPE_INDEX = "Index";
    public static final String TYPE_SYNONYM = "Synonym";
    public static final String TYPE_PACKAGE = "Package";
    public static final String TYPE_DBLINK = "DBLink";
    public static final String TYPE_USER = "User";
    public static final String TYPE_ROLE = "Role";
    public static final String TYPE_RULE = "Rule";
    public static final String TYPE_GROUP = "Group";
    public static final String TYPE_DOMAIN = "Domain";
    public static final String TYPE_GRANT = "Grant";
    public static final String TYPE_OBJECTTYPE = "Object Type";
    public static final String TYPE_DATATYPE = "DataType";
    private LinkedHashMap<String, ArrayList<MigrationObject>> objList = new LinkedHashMap();

    /**
     * @deprecated
     */
    public synchronized void alertNewObject(String type, DBObject obj) {
        ArrayList listValues = null;

        if (this.objList.containsKey(type)) {
            listValues = (ArrayList) this.objList.get(type);
        } else {
            listValues = new ArrayList();
            this.objList.put(type, listValues);
        }

        if (indexOfObject(listValues, obj) == -1)
            listValues.add(new MigrationObject(obj));
        else alertFail(type, obj);
    }

    public void alertNewTable(Table table) {
        alertNewObject("Table", table);
    }

    public void alertNewTrigger(Trigger trigger) {
        alertNewObject("Trigger", trigger);
    }

    public void alertNewView(View view) {
        alertNewObject("View", view);
    }

    public void alertNewSequence(Sequence seq) {
        alertNewObject("Sequence", seq);
    }

    public void alertNewProcedure(Procedure procedure) {
        alertNewObject("Procedure", procedure);
    }

    public void alertNewFunction(Function func) {
        alertNewObject("Function", func);
    }

    public void alertNewConstraint(Constraint constraint) {
        alertNewObject("Constraint", constraint);
    }

    public void alertNewIndex(Index index) {
        alertNewObject("Index", index);
    }

    public void alertNewSynonym(Synonym syn) {
        alertNewObject("Synonym", syn);
    }

    public void alertNewPackage(Package pkg) {
        alertNewObject("Package", pkg);
    }

    public void alertNewDBLinks(DBLink link) {
        alertNewObject("DBLink", link);
    }

    public void alertNewUser(User user) {
        alertNewObject("User", user);
    }

    public void alertNewRole(Role role) {
        alertNewObject("Role", role);
    }

    public void alertNewGrant(Grant grant) {
        alertNewObject("Grant", grant);
    }

    public void alertNewObjectType(ObjectType objectType) {
        alertNewObject("Object Type", objectType);
    }

    public void alertNewRule(Rule rule) {
        alertNewObject("Rule", rule);
    }

    public void alertNewGroup(Group group) {
        alertNewObject("Group", group);
    }

    public void alertNewDomain(Domain domain) {
        alertNewObject("Domain", domain);
    }

    public void alertNewType(DataType type) {
        alertNewObject("DataType", type);
    }

    /**
     * @deprecated
     */
    public synchronized void alertSuccess(String type, DBObject obj) {
        if (this.objList.containsKey(type)) {
            ArrayList listValues = (ArrayList) this.objList.get(type);
            int index = indexOfObject(listValues, obj);
            if (index >= 0)
                ((MigrationObject) listValues.get(index)).setStatus(Boolean.TRUE);
        }
    }

    public void alertSuccessTable(Table table) {
        alertSuccess("Table", table);
    }

    public void alertSuccessTrigger(Trigger trigger) {
        alertSuccess("Trigger", trigger);
    }

    public void alertSuccessView(View view) {
        alertSuccess("View", view);
    }

    public void alertSuccessSequence(Sequence seq) {
        alertSuccess("Sequence", seq);
    }

    public void alertSuccessProcedure(Procedure proc) {
        alertSuccess("Procedure", proc);
    }

    public void alertSuccessFunction(Function func) {
        alertSuccess("Function", func);
    }

    public void alertSuccessConstraint(Constraint constraint) {
        alertSuccess("Constraint", constraint);
    }

    public void alertSuccessIndex(Index index) {
        alertSuccess("Index", index);
    }

    public void alertSuccessSynonym(Synonym syn) {
        alertSuccess("Synonym", syn);
    }

    public void alertSuccessPackage(Package pkg) {
        alertSuccess("Package", pkg);
    }

    public void alertSuccessDBLink(DBLink link) {
        alertSuccess("DBLink", link);
    }

    public void alertSuccessUser(User user) {
        alertSuccess("User", user);
    }

    public void alertSuccessRole(Role role) {
        alertSuccess("Role", role);
    }

    public void alertSuccessGrant(Grant grant) {
        alertSuccess("Grant", grant);
    }

    public void alertSuccessObjectType(ObjectType objectType) {
        alertSuccess("Object Type", objectType);
    }

    public void alertSuccessRule(Rule rule) {
        alertSuccess("Rule", rule);
    }

    public void alertSuccessGroup(Group group) {
        alertSuccess("Group", group);
    }

    public void alertSuccessDomain(Domain domain) {
        alertSuccess("Domain", domain);
    }

    public void alertSuccessType(DataType type) {
        alertSuccess("DataType", type);
    }

    /**
     * @deprecated
     */
    public synchronized void alertFail(String type, DBObject obj) {
        if (this.objList.containsKey(type)) {
            ArrayList listValues = (ArrayList) this.objList.get(type);
            int index = indexOfObject(listValues, obj);
            if (index >= 0)
                ((MigrationObject) listValues.get(index)).setStatus(Boolean.FALSE);
        }
    }

    public void alertFailTable(Table table) {
        alertFail("Table", table);
    }

    public void alertFailPackage(Package pkg) {
        alertFail("Package", pkg);
    }

    private int indexOfObject(ArrayList<MigrationObject> list, DBObject obj) {
        for (int i = 0; i < list.size(); i++) {
            if (((MigrationObject) list.get(i)).getDBObject().equals(obj))
                return i;
        }
        return -1;
    }

    public String getSummary() {
        String newLine = System.getProperty("line.separator");
        String summary = "";

        String[] keys = (String[]) this.objList.keySet().toArray(new String[0]);
        for (int i = 0; i < keys.length; i++) {
            String key = keys[i];

            summary = summary + key + (key.equalsIgnoreCase("index") ? "es: " : "s: ") + getSuccessfulCount((ArrayList) this.objList.get(key)) + " " + ResourceHandler.getValue("INFO_MIGRATION_SUMMARY_OUT_OF", null) + " " + getTotalCount((ArrayList) this.objList.get(key)) + newLine;
        }

        summary = summary + newLine;
        summary = summary + ResourceHandler.getValue("INFO_MIGRATION_SUMMARY_TOTAL_OBJ", null) + ": " + getTotalCount() + newLine;
        summary = summary + ResourceHandler.getValue("INFO_MIGRATION_SUMMARY_SUCCESS_COUNT", null) + ": " + getSuccessfulCount() + newLine;
        summary = summary + ResourceHandler.getValue("INFO_MIGRATION_SUMMARY_FAIL_COUNT", null) + ": " + getFailedCount() + newLine;
//        summary = summary + ResourceHandler.getValue("INFO_MIGRATION_SUMMARY_SUCCESS_COUNT", null) + ": " + (getSuccessfulCount() + getFailedCount()) + newLine;
//        summary = summary + ResourceHandler.getValue("INFO_MIGRATION_SUMMARY_FAIL_COUNT", null) + ": " + (getFailedCount() - getFailedCount()) + newLine;


        String failedObjs = formatFailedObjects();
        if (failedObjs.trim().length() > 0) {
            summary = summary + newLine;
            summary = summary + ResourceHandler.getValue("INFO_MIGRATION_SUMMARY_FAIL_OBJ_LIST", null) + newLine;
//            summary = summary + "警告对象列表" + newLine;
            summary = summary + "======================" + newLine;
            summary = summary + failedObjs;
        }

        return summary;
    }

    private int getTotalCount(ArrayList<MigrationObject> table) {
        return table.size();
    }

    public int getTotalCount() {
        int count = 0;
        Object[] keys = this.objList.keySet().toArray();
        for (int i = 0; i < keys.length; i++) {
            count += getTotalCount((ArrayList) this.objList.get(keys[i]));
        }
        return count;
    }

    private int getSuccessfulCount(ArrayList<MigrationObject> table) {
        int success = 0;
        for (int i = 0; i < table.size(); i++) {
            if (((MigrationObject) table.get(i)).getStatus().equals(Boolean.TRUE)) {
                success++;
            }
        }
        return success;
    }

    public int getSuccessfulCount() {
        int count = 0;
        Object[] keys = this.objList.keySet().toArray();
        for (int i = 0; i < keys.length; i++) {
            count += getSuccessfulCount((ArrayList) this.objList.get(keys[i]));
        }
        return count;
    }

    private int getFailedCount(ArrayList<MigrationObject> table) {
        int failures = 0;
        for (int i = 0; i < table.size(); i++) {
            if (((MigrationObject) table.get(i)).getStatus().equals(Boolean.FALSE)) {
                failures++;
            }
        }
        return failures;
    }

    public int getFailedCount() {
        int count = 0;
        Object[] keys = this.objList.keySet().toArray();
        for (int i = 0; i < keys.length; i++) {
            count += getFailedCount((ArrayList) this.objList.get(keys[i]));
        }
        return count;
    }

    public int getFailedCount(String schema) {
        int count = 0;
        Object[] keys = this.objList.keySet().toArray();
        for (int i = 0; i < keys.length; i++) {
            ArrayList table = (ArrayList) this.objList.get(keys[i]);
            for (int j = 0; j < table.size(); j++) {
                if ((((MigrationObject) table.get(j)).getStatus().equals(Boolean.FALSE)) && (((schema == null) && (((MigrationObject) table.get(j)).getDBObject().getSchema() == null)) || ((((MigrationObject) table.get(j)).getDBObject().getSchema() != null) && (((MigrationObject) table.get(j)).getDBObject().getSchema().equals(schema))))) {
                    count++;
                }
            }
        }
        return count;
    }

    private String formatFailedObjects() {
        String newLine = System.getProperty("line.separator");
        String str = "";
        String[] keys = (String[]) this.objList.keySet().toArray(new String[0]);
        for (int i = 0; i < keys.length; i++) {
            ArrayList list = (ArrayList) this.objList.get(keys[i]);
            if (getFailedCount(list) == 0) {
                continue;
            }
            str = str + keys[i] + (keys[i].equalsIgnoreCase("index") ? "es" : "s") + newLine + "--------------------" + newLine;
            int count = 1;
            for (int j = 0; j < list.size(); j++) {
                if (!((MigrationObject) list.get(j)).getStatus().equals(Boolean.FALSE))
                    continue;
                str = str + count++ + ". " + ((MigrationObject) list.get(j)).getFullName() + newLine;
            }

            str = str + newLine;
        }
        return str;
    }

    public ArrayList<DBObject> getFailedDBObjects(String schema, String objtype) {
        ArrayList list = new ArrayList();
        ArrayList typeList = (ArrayList) this.objList.get(objtype);
        if (typeList != null) {
            for (int i = 0; i < typeList.size(); i++) {
                if ((((MigrationObject) typeList.get(i)).getStatus().equals(Boolean.FALSE)) && (((schema == null) && (((MigrationObject) typeList.get(i)).getDBObject().getSchema() == null)) || ((((MigrationObject) typeList.get(i)).getDBObject().getSchema() != null) && (((MigrationObject) typeList.get(i)).getDBObject().getSchema().equals(schema))))) {
                    list.add(((MigrationObject) typeList.get(i)).getDBObject());
                }
            }
        }
        return list;
    }

    public ConstraintList getFailedConstraints(String schema) {
        return new ConstraintList(getFailedDBObjects(schema, "Constraint"));
    }

    public FunctionList getFailedFunctions(String schema) {
        return new FunctionList(getFailedDBObjects(schema, "Function"));
    }

    public IndexList getFailedIndexes(String schema) {
        return new IndexList(getFailedDBObjects(schema, "Index"));
    }

    public PackageList getFailedPackages(String schema) {
        return new PackageList(getFailedDBObjects(schema, "Package"));
    }

    public ProcedureList getFailedProcedures(String schema) {
        return new ProcedureList(getFailedDBObjects(schema, "Procedure"));
    }

    public SynonymList getFailedSynonyms(String schema) {
        return new SynonymList(getFailedDBObjects(schema, "Synonym"));
    }

    public SequenceList getFailedSequences(String schema) {
        return new SequenceList(getFailedDBObjects(schema, "Sequence"));
    }

    public TableList getFailedTables(String schema) {
        return new TableList(getFailedDBObjects(schema, "Table"));
    }

    public TriggerList getFailedTriggers(String schema) {
        return new TriggerList(getFailedDBObjects(schema, "Trigger"));
    }

    public ViewList getFailedViews(String schema) {
        return new ViewList(getFailedDBObjects(schema, "View"));
    }

    public ObjectTypeList getFailedObjectTypes(String schema) {
        return new ObjectTypeList(getFailedDBObjects(schema, "Object Type"));
    }

    public DomainList getFailedDomains(String schema) {
        return new DomainList(getFailedDBObjects(schema, "Domain"));
    }

    public boolean hasSuccessStatus(String type, DBObject obj) {
        if (this.objList.containsKey(type)) {
            ArrayList listValues = (ArrayList) this.objList.get(type);
            int index = indexOfObject(listValues, obj);
            if (index >= 0) {
                return ((MigrationObject) listValues.get(index)).getStatus().booleanValue();
            }
        }

        return false;
    }

    public void resetList() {
        this.objList.clear();
    }
}

/* 

 * 
 */